﻿using System.Text;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Communication.Net.Web;
using UtilZ.Dotnet.Ex.Json;
using UtilZ.Dotnet.Ex.Log;
using UtilZ.Dotnet.Ex.Model;

namespace UtilZFileServer
{
    [Route("api/v1/fileService")]
    internal class FileServerApi
    {
        /// <summary>
        /// key:目录名;value:目录全路径
        /// </summary>
        private readonly IReadOnlyDictionary<string, string> _rootDirDic;

        public FileServerApi(List<PathItem> localPaths)
        {
            var rootDirDic = new Dictionary<string, string>();
            string name;
            foreach (var localPath in localPaths)
            {
                name = localPath.Alias.Trim().ToLower();
                if (rootDirDic.ContainsKey(name))
                {
                    throw new ArgumentException($"路径别名\"{localPath.Alias}\"重复");
                }

                rootDirDic.Add(name, localPath.Path);
            }

            this._rootDirDic = rootDirDic;
        }

        private bool TryGet(string path, out string rootDir, out string modPath, out string err)
        {
            rootDir = null;
            modPath = null;
            err = null;

            if (string.IsNullOrEmpty(path))
            {
                err = "目标路径不能为空";
                return false;
            }

            path = path.Trim(PathEx.LeftSlash, PathEx.RightSlash);

            int index = path.IndexOf(PathEx.LeftSlash);
            if (index < 0)
            {
                index = path.IndexOf(PathEx.RightSlash);
            }

            string alias;
            if (index < 0)
            {
                alias = path.ToLower();
            }
            else
            {
                alias = path.Substring(0, index).ToLower();
            }


            if (!this._rootDirDic.TryGetValue(alias, out rootDir))
            {
                err = $"根目录\"{alias}\"对应的目录不存在";
                return false;
            }

            if (index > 0)
            {
                modPath = path.Substring(index).ToLower();
            }

            return true;
        }

        [HttpGet("getFileSystemInfos?path={path}")]
        public ApiResult GetFileSystemInfos(string path)
        {
            try
            {
                List<FileItem> list = new List<FileItem>();
                if (string.IsNullOrWhiteSpace(path))
                {
                    foreach (var kv in this._rootDirDic)
                    {
                        if (Directory.Exists(kv.Value))
                        {
                            var reqDirInfo = new DirectoryInfo(kv.Value);
                            list.Add(new FileItem()
                            {
                                Name = kv.Key,
                                Url = kv.Key,
                                CreateTime = reqDirInfo.CreationTime,
                                LastModifyTime = reqDirInfo.LastWriteTime,
                                Count = reqDirInfo.GetFileSystemInfos().Length
                            });
                        }
                    }
                }
                else
                {
                    string rootDir, modPath, err;
                    if (!this.TryGet(path, out rootDir, out modPath, out err))
                    {
                        return new ApiResult(ApiResultStatus.Fail, err);
                    }

                    string targetDir = PathEx.Combine(PathType.Local, rootDir, modPath);
                    if (Directory.Exists(targetDir))
                    {
                        var reqDirInfo = new DirectoryInfo(targetDir);
                        DirectoryInfo[] dirInfos = reqDirInfo.GetDirectories();
                        foreach (var dirInfo in dirInfos)
                        {
                            try
                            {
                                list.Add(new FileItem()
                                {
                                    Name = dirInfo.Name,
                                    Url = dirInfo.Name,
                                    CreateTime = dirInfo.CreationTime,
                                    LastModifyTime = dirInfo.LastWriteTime,
                                    Count = dirInfo.GetFileSystemInfos().Length
                                });
                            }
                            catch (UnauthorizedAccessException)
                            {

                            }
                        }

                        FileInfo[] fileInfos = reqDirInfo.GetFiles();
                        foreach (var fileInfo in fileInfos)
                        {
                            try
                            {
                                list.Add(new FileItem()
                                {
                                    Name = fileInfo.Name,
                                    Url = fileInfo.Name,
                                    CreateTime = fileInfo.CreationTime,
                                    LastModifyTime = fileInfo.LastWriteTime,
                                    Length = fileInfo.Length
                                });
                            }
                            catch (UnauthorizedAccessException)
                            {

                            }
                        }
                    }
                }

                string json = JsonSerializer.SerializeObject(list);
                return new ApiResult(ApiResultStatus.Succes, json);
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
                return new ApiResult(ApiResultStatus.Exception, ex.Message);
            }
        }

        [HttpGet("searchFileSystemInfos?searchKey={searchKey}&path={path}")]
        public ApiResult SearchFileSystemInfos(string searchKey, string path)
        {
            try
            {
                string searchPattern = $"*{searchKey}*.*";
                List<FileItem> listStartsWith = new List<FileItem>();
                List<FileItem> listContains = new List<FileItem>();
                List<FileItem> listEndsWith = new List<FileItem>();
                List<FileItem> list;

                if (string.IsNullOrWhiteSpace(path))
                {
                    foreach (var kv in this._rootDirDic)
                    {
                        if (Directory.Exists(kv.Value))
                        {
                            var reqDirInfo = new DirectoryInfo(kv.Value);
                            FileSystemInfo[] fileSystemInfos = reqDirInfo.GetFileSystemInfos(searchPattern, SearchOption.AllDirectories);
                            foreach (var fileSystemInfo in fileSystemInfos)
                            {
                                if (fileSystemInfo.Name.StartsWith(searchKey, StringComparison.OrdinalIgnoreCase))
                                {
                                    list = listStartsWith;
                                }
                                else if (fileSystemInfo.Name.EndsWith(searchKey, StringComparison.OrdinalIgnoreCase))
                                {
                                    list = listEndsWith;
                                }
                                else
                                {
                                    list = listContains;
                                }

                                if (fileSystemInfo is DirectoryInfo)
                                {
                                    var dirInfo = (DirectoryInfo)fileSystemInfo;
                                    list.Add(new FileItem()
                                    {
                                        Name = $"/{kv.Key}{dirInfo.FullName.Substring(kv.Value.Length)}".Replace(PathEx.LeftSlash, PathEx.RightSlash),
                                        Url = dirInfo.FullName.Substring(kv.Value.Length),
                                        CreateTime = dirInfo.CreationTime,
                                        LastModifyTime = dirInfo.LastWriteTime,
                                        Count = dirInfo.GetFileSystemInfos().Length
                                    });
                                }
                                else if (fileSystemInfo is FileInfo)
                                {
                                    var fileInfo = (FileInfo)fileSystemInfo;
                                    list.Add(new FileItem()
                                    {
                                        Name = $"/{kv.Key}{fileInfo.FullName.Substring(kv.Value.Length)}".Replace(PathEx.LeftSlash, PathEx.RightSlash),
                                        Url = fileInfo.FullName.Substring(kv.Value.Length),
                                        CreateTime = fileInfo.CreationTime,
                                        LastModifyTime = fileInfo.LastWriteTime,
                                        Length = fileInfo.Length
                                    });
                                }
                                else
                                {
                                    //忽略
                                }

                            }
                        }
                    }
                }
                else
                {
                    string rootDir, modPath, err;
                    if (!this.TryGet(path, out rootDir, out modPath, out err))
                    {
                        return new ApiResult(ApiResultStatus.Fail, err);
                    }

                    string targetDir = PathEx.Combine(PathType.Local, rootDir, modPath);
                    if (Directory.Exists(targetDir))
                    {
                        var reqDirInfo = new DirectoryInfo(targetDir);
                        FileSystemInfo[] fileSystemInfos = reqDirInfo.GetFileSystemInfos(searchPattern, SearchOption.AllDirectories);
                        foreach (var fileSystemInfo in fileSystemInfos)
                        {
                            if (fileSystemInfo.Name.StartsWith(searchKey, StringComparison.OrdinalIgnoreCase))
                            {
                                list = listStartsWith;
                            }
                            else if (fileSystemInfo.Name.EndsWith(searchKey, StringComparison.OrdinalIgnoreCase))
                            {
                                list = listEndsWith;
                            }
                            else
                            {
                                list = listContains;
                            }

                            if (fileSystemInfo is DirectoryInfo)
                            {
                                var dirInfo = (DirectoryInfo)fileSystemInfo;
                                list.Add(new FileItem()
                                {
                                    Name = $"{dirInfo.FullName.Substring(targetDir.Length + 1)}".Replace(PathEx.LeftSlash, PathEx.RightSlash),
                                    Url = dirInfo.FullName.Substring(rootDir.Length),
                                    CreateTime = dirInfo.CreationTime,
                                    LastModifyTime = dirInfo.LastWriteTime,
                                    Count = dirInfo.GetFileSystemInfos().Length
                                });
                            }
                            else if (fileSystemInfo is FileInfo)
                            {
                                var fileInfo = (FileInfo)fileSystemInfo;
                                list.Add(new FileItem()
                                {
                                    Name = $"{fileInfo.FullName.Substring(targetDir.Length + 1)}".Replace(PathEx.LeftSlash, PathEx.RightSlash),
                                    Url = fileInfo.FullName.Substring(rootDir.Length),
                                    CreateTime = fileInfo.CreationTime,
                                    LastModifyTime = fileInfo.LastWriteTime,
                                    Length = fileInfo.Length
                                });
                            }
                            else
                            {
                                //忽略
                            }

                        }
                    }
                }

                var resultList = new List<FileItem>(listStartsWith.Count + listContains.Count + listEndsWith.Count);
                resultList.AddRange(listStartsWith);
                resultList.AddRange(listContains);
                resultList.AddRange(listEndsWith);
                string json = JsonSerializer.SerializeObject(resultList);
                return new ApiResult(ApiResultStatus.Succes, json);
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
                return new ApiResult(ApiResultStatus.Exception, ex.Message);
            }
        }

        [HttpGet("createDirectory?path={path}")]
        public ApiResult CreateDirectory(string path)
        {
            try
            {
                string rootDir, modPath, err;
                if (this.TryGet(path, out rootDir, out modPath, out err))
                {
                    string targetDir = PathEx.Combine(PathType.Local, rootDir, modPath);
                    Directory.CreateDirectory(targetDir);
                    Loger.Info($"创建目录\"{path}\"成功");
                    return new ApiResult(ApiResultStatus.Succes, "ok");
                }
                else
                {
                    return new ApiResult(ApiResultStatus.Fail, err);
                }
            }
            catch (UnauthorizedAccessException uaex)
            {
                Loger.Error(uaex, $"创建目录\"{path}\"失败");
                return new ApiResult(ApiResultStatus.Exception, uaex.Message);
            }
            catch (Exception ex)
            {
                Loger.Error(ex, $"创建目录\"{path}\"失败");
                return new ApiResult(ApiResultStatus.Exception, ex.Message);
            }
        }

        [HttpPost("delete")]
        public ApiResult Delete(DeleteData deleteData)
        {
            try
            {
                if (deleteData == null ||
                    deleteData.List == null ||
                    deleteData.List.Count == 0)
                {
                    return new ApiResult(ApiResultStatus.Succes, "ok");
                }

                string rootDir, modPath, err;
                if (this.TryGet(deleteData.Path, out rootDir, out modPath, out err))
                {
                    string targetPath = null;
                    foreach (var item in deleteData.List)
                    {
                        try
                        {
                            targetPath = PathEx.Combine(PathType.Local, rootDir, modPath, item.Name);
                            if (item.Length > 0)
                            {
                                if (File.Exists(targetPath))
                                {
                                    File.Delete(targetPath);
                                    Loger.Info($"删除文件\"{targetPath}\"成功");
                                }
                                else
                                {
                                    Loger.Warn($"要删除的文件\"{targetPath}\"不存在");
                                }
                            }
                            else
                            {
                                DirectoryInfoEx.DeleteFolder(targetPath);
                                Loger.Info($"删除目录\"{targetPath}\"成功");
                            }
                        }
                        catch (UnauthorizedAccessException uaex)
                        {
                            Loger.Warn(uaex, $"删除目标\"{targetPath}\"失败");
                        }
                    }

                    return new ApiResult(ApiResultStatus.Succes, "ok");
                }
                else
                {
                    return new ApiResult(ApiResultStatus.Fail, err);
                }
            }
            catch (Exception ex)
            {
                Loger.Error(ex, $"删除目标失败");
                return new ApiResult(ApiResultStatus.Exception, ex.Message);
            }
        }

        [HttpPost("uploadFile?path={path}")]
        public ApiResult UploadFile(HttpActionContext actionContext, string path, [FromBody] HttpFormData formData)
        {
            try
            {
                string rootDir, modPath, err;
                if (!this.TryGet(path, out rootDir, out modPath, out err))
                {
                    return new ApiResult(ApiResultStatus.Fail, err);
                }

                string fileDir = PathEx.Combine(PathType.Local, rootDir, modPath);
                string filePath;
                var httpResponse = new HttpResponse(actionContext.Request.Connection);
                StringBuilder sb = null;

                foreach (HttpFile file in formData.Files)
                {
                    filePath = PathEx.Combine(PathType.Local, fileDir, file.Filename);
                    DirectoryInfoEx.CheckFilePathDirectory(filePath);
                    if (File.Exists(filePath))
                    {
                        if (sb == null)
                        {
                            sb = new StringBuilder();
                        }
                        else
                        {
                            sb.Append(';');
                        }
                        sb.Append($"上传文件\"{file.Name}\"失败,文件名重复");
                        Loger.Warn($"上传文件\"{file.Name}\"失败,文件名重复");
                        continue;
                    }

                    using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                    {
                        file.CopyTo(fs);
                    }
                    Loger.Info($"上传文件\"{file.Name}\"成功");
                }

                if (sb == null)
                {
                    return new ApiResult(ApiResultStatus.Succes, "ok");
                }
                else
                {
                    return new ApiResult(ApiResultStatus.Fail, sb.ToString());
                }
            }
            catch (Exception ex)
            {
                Loger.Error(ex, $"上传文件失败");
                return new ApiResult(ApiResultStatus.Exception, ex.Message);
            }
        }


        /*
        //http://192.168.10.96:23018/testApi/getName
        [HttpGet("getFileSystemInfos?targetDir={targetDir}")]
        public ApiResult DowloadFile(string fileName)
        {
            string filePath = null;
            foreach (var dir in this._dirList)
            {
                //文本内容类的需要将内容读取出来
                filePath = PathEx.Combine(PathType.Local, dir, fileName);
                if (File.Exists(filePath))
                {
                    break;
                }
                else
                {
                    filePath = null;
                }
            }

            if (filePath == null)
            {
                return new ApiResult(ApiResultStatus.Fail, $"文件\"{fileName}\"不存在");
            }

            //到根目录中找资源
            if (File.Exists(filePath))
            {
                //根目录中找到请求的资源
                this._urlSourceFilePathCache.Add(url, filePath, urlCacheMilliseconds);
                return filePath;
            }

            //到其它资源目录中找资源
            if (this._config.SourceDirs == null)
            {
                return null;
            }

            foreach (string sourceDir in this._config.SourceDirs)
            {
                filePath = PathEx.Combine(PathType.Local, sourceDir, fileName);
                if (File.Exists(filePath))
                {
                    //资源目录中找到请求的资源
                    this._urlSourceFilePathCache.Add(url, filePath, urlCacheMilliseconds);
                    return filePath;
                }
            }
        }
        */




    }

}
